package com.study.ming.studydemo.thd;

import org.junit.Test;

import java.util.Random;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * 多线程下建议使用ThreadLocalRandom
 */
public class RandomTimeTest {
    // 要产生的随机数数量
    public static final int GEN_COUNT = 10000000;
    // 参与工作的线程数量
    public static final int THREAD_COUNT = 4;
    // 定义线程池
    static ExecutorService exe = Executors.newFixedThreadPool(THREAD_COUNT);

    public static Random rnd = new Random(123);
    public static ThreadLocalRandom tlRnd = ThreadLocalRandom.current();

    // 由ThreadLocal封装的Random
    public static ThreadLocal<Random> tRnd = ThreadLocal.withInitial(() -> new Random(123));

    public static class RndTask implements Callable<Long> {
        private int mode = 0;

        public RndTask(int mode) {
            this.mode = mode;
        }

        // 创建随机数的方式
        public Random getRandom() {
            if (mode == 0)
                return rnd;
            else if (mode == 1)
                return tRnd.get();
            else if (mode == 2)
                return tlRnd;
            else
                return null;
        }

        /**
         * 每个线程产生若干随机数，完成工作后记录幷返回所消耗的时间
         */
        @Override
        public Long call() throws Exception {
            long b = System.currentTimeMillis();
            for (int i = 0; i < GEN_COUNT; i++)
                getRandom().nextInt();
            long e = System.currentTimeMillis();
            System.out.println(Thread.currentThread().getName() + " spend " + (e - b) + "ms");
            return e - b;
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Future<Long>[] futures = new Future[THREAD_COUNT];
        // 多线程共享Random实例
        for (int i = 0; i < THREAD_COUNT; i++)
            futures[i] = exe.submit(new RndTask(0));
        long totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += futures[i].get();
        System.out.println("多线程同时访问同一个Random实例：" + totaltime + "ms");

        // 使用ThreadLocal情况
        for (int i = 0; i < THREAD_COUNT; i++)
            futures[i] = exe.submit(new RndTask(1));
        totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += futures[i].get();
        System.out.println("使用ThreadLocal包装Random实例: " + totaltime + "ms");

        // 使用ThreadLocalRandom情况
        for (int i = 0; i < THREAD_COUNT; i++)
            futures[i] = exe.submit(new RndTask(2));
        totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += futures[i].get();
        System.out.println("使用ThreadLocalRandom实例: " + totaltime + "ms");
        exe.shutdown();


        /*long totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += exe.submit(new RndTask(0)).get();
        System.out.println("多线程同时访问同一个Random实例：" + totaltime + "ms");

        totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += exe.submit(new RndTask(1)).get();
        System.out.println("使用ThreadLocal包装Random实例：" + totaltime + "ms");

        totaltime = 0;
        for (int i = 0; i < THREAD_COUNT; i++)
            totaltime += exe.submit(new RndTask(2)).get();
        System.out.println("使用ThreadLocalRandom实例：" + totaltime + "ms");
        exe.shutdown();*/
    }

    @Test
    public void sdfasdf() {
        String u = UUID.randomUUID().toString();
        System.out.println(u);
    }
}